// Copyright 2010, Shuo Chen.  All rights reserved.
// http://code.google.com/p/muduo/
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.

// Author: Shuo Chen (chenshuo at chenshuo dot com)
//
// This is a public header file, it must only include public header files.

#ifndef MUDUO_NET_EVENTLOOP_H
#define MUDUO_NET_EVENTLOOP_H

#include <atomic>
#include <functional>
#include <vector>

#include <boost/any.hpp>

#include "muduo/base/CurrentThread.h"
#include "muduo/base/Mutex.h"
#include "muduo/base/Timestamp.h"
#include "muduo/net/Callbacks.h"
#include "muduo/net/TimerId.h"

namespace muduo {
namespace net {

class Channel;
class Poller;
class TimerQueue;

///
/// 每个线程最多一个
///
/// 接口类，不需要暴露太多细节
class EventLoop : noncopyable
{
public:
    typedef std::function<void()> Functor;

    EventLoop();
    ~EventLoop();  // force out-line dtor, for std::unique_ptr members.

    ///
    /// Loops forever.
    ///
    /// 必须在创建对象的同一个线程中调用
    ///
    void loop();

    /// Quits loop.
    ///
    /// 这不是100%线程安全的，如果你通过一个原始指针调用，
    /// 为了100%的安全，最好通过shared_ptr<EventLoop>调用。
    void quit();

    ///
    /// Time when poll returns, usually means data arrival.
    /// 轮询返回时间，通常表示数据到达。
    Timestamp pollReturnTime() const { return pollReturnTime_; }

    int64_t iteration() const { return iteration_; }

    /// 在循环线程中立即运行回调。
    /// 唤醒循环，并运行cb。
    /// 如果在同一个循环线程中，则在函数内运行cb。
    /// 可以安全地从其他线程调用。
    void runInLoop(Functor cb);
    /// 在循环线程中排队回调。
    /// 池化完成后运行。
    /// 可以安全地从其他线程调用。
    void queueInLoop(Functor cb);

    size_t queueSize() const;

    // timers

    ///
    /// 在time时运行回调。
    /// 可以安全的从其他线程调用
    ///
    TimerId runAt(Timestamp time, TimerCallback cb);
    ///
    /// 延迟delay秒后调用
    /// Safe to call from other threads.
    ///
    TimerId runAfter(double delay, TimerCallback cb);
    ///
    /// 每间隔interval秒后调用
    /// Safe to call from other threads.
    ///
    TimerId runEvery(double interval, TimerCallback cb);
    ///
    /// 取消定时器
    /// Safe to call from other threads.
    ///
    void cancel(TimerId timerId);

    // 内部使用
    void wakeup();
    void updateChannel(Channel* channel);
    void removeChannel(Channel* channel);
    bool hasChannel(Channel* channel);

    // pid_t threadId() const { return threadId_; }
    void assertInLoopThread()
    {
        if (!isInLoopThread()) {
            abortNotInLoopThread();
        }
    }
    bool isInLoopThread() const { return threadId_ == CurrentThread::tid(); }
    // bool callingPendingFunctors() const { return callingPendingFunctors_; }
    bool eventHandling() const { return eventHandling_; }

    void setContext(const boost::any& context) { context_ = context; }

    const boost::any& getContext() const { return context_; }

    boost::any* getMutableContext() { return &context_; }

    static EventLoop* getEventLoopOfCurrentThread();

private:
    void abortNotInLoopThread();
    void handleRead();  // waked up
    void doPendingFunctors();

    void printActiveChannels() const;  // DEBUG

    typedef std::vector<Channel*> ChannelList;

    bool                        looping_; /* atomic */
    std::atomic<bool>           quit_;
    bool                        eventHandling_;          /* atomic */
    bool                        callingPendingFunctors_; /* atomic */
    int64_t                     iteration_;
    const pid_t                 threadId_;
    Timestamp                   pollReturnTime_;
    std::unique_ptr<Poller>     poller_;
    std::unique_ptr<TimerQueue> timerQueue_;
    int                         wakeupFd_;
    // unlike in TimerQueue, which is an internal class,
    // we don't expose Channel to client.
    std::unique_ptr<Channel> wakeupChannel_;
    boost::any               context_;

    // scratch variables
    ChannelList activeChannels_;
    Channel*    currentActiveChannel_;

    mutable MutexLock mutex_;
    // 挂起函数，如果number
    std::vector<Functor> pendingFunctors_ GUARDED_BY(mutex_);
};

}  // namespace net
}  // namespace muduo

#endif  // MUDUO_NET_EVENTLOOP_H
